from Djoser import *
#~ from Djoser.djtools import *
from interpret import  *
from kthread import  *
import sys

#Note that when this class is created, it steals stdout and stderr

class DjPrompt(DjApplication):
	interpreter = None
	lastResult = '0'
	useThreads = False
	def __init__(self, reference=None, useThreads=False, addImports=True): #By default, use threads. Makes execution slower, but you can press Ctrl+. to stop execution.
		if reference==None:
			DjApplication.__init__(self)
			window = None
		else: #Attach to an application
			DjApplication.__init__(self, reference._tkroot)
			window = reference.window
		
		# This window will take the place of stdout and stderr
		self.save_stdout = sys.stdout
		self.save_stderr = sys.stderr
		sys.stdout = PseudoFile(self.print_result)
		sys.stderr = PseudoFile(self.print_result)
		
		#extract locals by using a reference. This allows expressions like 'self.title = '3'' even though self doesn't refer to the current class
		dictlocals = {'self':reference,'window':window}
		
		self.interpreter = ThreadInterpreter(useThread = useThreads, locals = dictlocals)
		if addImports: #Add to the namespace
			self.interpreter.eval('from Djoser.djtools.djcontrols.tkwrappers.pywrappers import *')
			self.interpreter.eval('from Djoser import *')
			#~ self.interpreter.eval('from Djoser.djtools.djcontrols.tkwrappers.tk_system_dialog import *')
		
		self.history = ['']
		self.historyIndex = 0
		self.useThreads = useThreads
	
	def restore_stdout(self):
		sys.stdout = self.save_stdout
		sys.stderr = self.save_stderr
		
	
	def layout(self,window):
		window.frame(V, layout='fill+')
		
		window.label('DjoserPrompt')
		o = window.frame(V, layout='fill+')
		self.fldEntry = window.field('1+1', scrollbar=True, wrap='word', width=50, height=2, layout='fillx-')
		self.fldResult = window.field(scrollbar=True, wrap='none', width=50, height=4, layout='fill+')
		window.endframe()
		window.endframe()
		window.add_all()
		
		window.bind('<Control-.>', self.interrupt)
		window.set_style('tool')
		window.title = 'DjoserPrompt'
		
		
		self.fldEntry.bind('<Key>', self.onkey)
		
		# Ctrl+A binding
		self.fldEntry.select_all_binding()
		self.fldResult.select_all_binding()
	
	def onkey(self, event=None):
		#~ self.print_result((event.keycode, event.keysym))
		mods=''
		if event.state & 0x00000004: mods += 'Ctrl+'
		if event.state & 0x00020000: mods += 'Alt+'
		if event.state & 0x00000001: mods += 'Shift+'
		if mods=='' and event.keysym=='Return':
			return self.go()
			
		elif mods=='' and event.keysym=='Up':
			if self.historyIndex<=0:
				self.fldEntry.text = ''
				self.historyIndex = -1
			else:
				self.historyIndex-=1
				self.fldEntry.text = self.history[self.historyIndex]
			return 'break'
		elif mods=='' and event.keysym=='Down':
			if self.historyIndex>=len(self.history)-1:
				self.fldEntry.text = ''
				self.historyIndex = len(self.history)
			else:
				self.historyIndex+=1
				self.fldEntry.text = self.history[self.historyIndex]
			return 'break'
		elif len(self.fldEntry.text)==1 and event.keysym in ('asterisk','slash','plus','minus'):
			self.fldEntry.insert_text('ans')
			return #Don't return break, let the key be sent
		elif event.keysym=='Escape':
			self.window.destroy()
	
	def go(self):
		if self.interpreter.busy:
			self.beep()
			return 'break'
		else:
			s = self.fldEntry.text.strip()
			if s.endswith(':'):
				return #probably an unfinished statement
			
			self.history.append(s)
			self.historyIndex = len(self.history)
			
			s = self.preprocessInput(s)
			self.fldResult.insert_text('\n>'+s+'\n\t', True)
			self.go_eval(s)
			self.fldResult.scrollto_end()
			
			self.fldEntry.text = ''
			return 'break'
			
	def go_eval(self, s):
		s = s.replace('ans',self.lastResult)
			
		if s=='clr' or s=='clr()':
			self.fldResult.text = ''
		elif s=='clrmem' or s=='clrmem()':
			#Reset interpretter
			self.interpreter.clear_locals()
		else:
			# This will end up calling resultCallback which will write the results
			self.interpreter.eval(s)
	
	def preprocessInput(self, s):
		return s
	
	def interrupt(self, event=None):
		if self.useThreads:
			self.interpreter.stop_thread()
		else:
			self.print_result('Execution can be stopped only if the prompt is set to use threads.')
	
	def print_result(self, s):
		if len(s.strip())==0: return
		if len(s): self.lastResult = s
		s = str(s)
		
		s = s.replace('\r\n','\n').replace('File "<input>", line 1','') \
			.replace('Traceback (most recent call last):','').replace(', in <module>','')
		s = s.strip('\n').replace('\n\n','\n')
		
		self.fldResult.insert_text(s + '\n', True)
		self.fldResult.scrollto_end()
	
